﻿using System;
using System.Data;
using System.IO;
using System.Windows.Forms;

namespace CmdPrep.Frontends
{
    public partial class CmdControl : UserControl
    {       
        #region Private data

        private DataTable   cmdFilesDataTable_;
        private DataView    cmdInputDataView_;
        private DataView    cmdOutputDataView_;
        
        #endregion   

        #region Private methods
            
        private void updateControlStates()
        {
            inputCmdButton.Enabled        = true;
            outputCmdButton.Enabled        = inputCmdListBox.SelectedIndex > -1;
            processCmdButton.Enabled    = ! string.IsNullOrEmpty(outputCmdListBox.SelectedValue as string);
            clearCmdButton.Enabled        = cmdFilesDataTable_.Rows.Count > 0;
        }
        
        private void updateStatusLabel() {
            // Looks like this already is implemented somehow !!!
        }
        
        #endregion

        #region Public events

        public delegate void StatusChangedEventHandler(string statusText);
        public event StatusChangedEventHandler statusChanged;
                        
        public delegate void InputCmdFileRequestEventHandler();
        public event InputCmdFileRequestEventHandler inputCmdFileRequested;
                        
        public delegate void OutputCmdFileRequestEventHandler(string fileNameHint);
        public event OutputCmdFileRequestEventHandler outputCmdFileRequested;
                        
        public delegate void ProcessCmdFileRequestEventHandler(string inputFullName, 
                                                               string outputFullName,
                                                               bool keepEqualSign,
                                                               bool skipEmptyLines);
        public event ProcessCmdFileRequestEventHandler processCmdFileRequested;
                        
        public delegate void DeleteCmdFileRequestEventHandler(string fullName);
        public event DeleteCmdFileRequestEventHandler deleteCmdFileRequested;
                        
        public delegate void EditCmdFileRequestEventHandler(string fullName);
        public event EditCmdFileRequestEventHandler editCmdFileRequested;
                        
        public delegate void DiffCmdFilesRequestEventHandler(string fullName1, string fullName2);
        public event DiffCmdFilesRequestEventHandler diffCmdFilesRequested;
        
        #endregion 

        #region Public foundation

        public CmdControl()
        {
            InitializeComponent();
            
            cmdFilesDataTable_ = new DataTable();
            cmdFilesDataTable_.Columns.Add(new DataColumn("inputFileName", Type.GetType("System.String")));
            cmdFilesDataTable_.Columns.Add(new DataColumn("inputFullName", Type.GetType("System.String")));
            cmdFilesDataTable_.Columns.Add(new DataColumn("outputFileName", Type.GetType("System.String")));
            cmdFilesDataTable_.Columns.Add(new DataColumn("outputFullName", Type.GetType("System.String")));
            
            cmdInputDataView_ = new DataView(cmdFilesDataTable_);
            cmdInputDataView_.RowFilter = "";
            inputCmdListBox.DataSource = cmdInputDataView_;
            inputCmdListBox.ValueMember = "inputFullName";
            inputCmdListBox.DisplayMember = "inputFileName";

            cmdOutputDataView_ = new DataView(cmdFilesDataTable_);
            cmdOutputDataView_.RowFilter = "LEN(outputFileName) > 0";
            outputCmdListBox.DataSource = cmdInputDataView_;
            outputCmdListBox.ValueMember = "outputFullName";
            outputCmdListBox.DisplayMember = "outputFileName";
            
            updateControlStates();
        }
        
        #endregion

        #region Public methods

        public void addInputCmdFileIfExclusive(DataRow cmdInputDataRow)
        {
            if (cmdInputDataRow == null)
                return;
            
            string cmdInputFullName = cmdInputDataRow["fullName"] as string;
            if (cmdInputFullName == null)
                return;
            
            addInputCmdFileIfExclusive(cmdInputFullName);
        }

        public void addInputCmdFileIfExclusive(string cmdInputFullName)
        {
            FileInfo cmdInputFileInfo = new FileInfo(cmdInputFullName);
            addInputCmdFileIfExclusive(cmdInputFileInfo);
        }

        public void addInputCmdFileIfExclusive(FileInfo cmdInputFileInfo)
        {
            bool isExclusive = true;
            foreach (DataRow dataRow in cmdFilesDataTable_.Rows)
                isExclusive &= ! dataRow["inputFileName"].Equals(cmdInputFileInfo.Name);
            
            if (! isExclusive)
                return;
            
            DataRow newRow = cmdFilesDataTable_.NewRow();
            newRow["inputFileName"] = cmdInputFileInfo.Name;
            newRow["inputFullName"] = cmdInputFileInfo.FullName;
            cmdFilesDataTable_.Rows.Add(newRow);
            
            updateControlStates();
            statusChanged("Input file added: " +cmdInputFileInfo.FullName);
        }
        
        public void addOutputCmdFile(string outputCmdFullName)
        {
            if (inputCmdListBox.SelectedIndex < 0)
                return;
            
            FileInfo outputCmdFileInfo = new FileInfo(outputCmdFullName);
            
            DataRow dataRow = cmdFilesDataTable_.Rows[inputCmdListBox.SelectedIndex];
            dataRow["outputFileName"] = outputCmdFileInfo.Name;
            dataRow["outputFullName"] = outputCmdFileInfo.FullName;

            updateControlStates();
            statusChanged("Output file added: " +outputCmdFileInfo.FullName);
        }        
        
        public void clearInputCmdFile(string inputCmdFullName)
        {
            DataRow[] rowsToDelete = cmdFilesDataTable_.Select("inputFullName like '" + inputCmdFullName + "'");
            
            for (int i = 0; i < rowsToDelete.Length; i++)
                rowsToDelete[i].Delete();
            
            cmdFilesDataTable_.AcceptChanges();
        }
        
        public void clearOutputCmdFile(string outputCmdFullName)
        {
            DataRow[] rowsToClear = cmdFilesDataTable_.Select("outputFullName like '" + outputCmdFullName + "'");

            for (int i = 0; i < rowsToClear.Length; i++)
            {
                rowsToClear[i]["outputFileName"] = "";
                rowsToClear[i]["outputFullName"] = "";
            }
        }
        
        #endregion

        #region    Private event handlers
        
        private void handleClearButtonClick(object sender, EventArgs e)
        {
            if (clearInputCmdCheckBox.Checked)
                cmdFilesDataTable_.Clear();
            
            if (clearOutputCmdCheckBox.Checked)
            {
                foreach (DataRow dataRow in cmdFilesDataTable_.Rows)
                {
                    dataRow["outputFileName"] = "";
                    dataRow["outputFullName"] = "";
                }
            }
        
            if (!clearInputCmdCheckBox.Checked && !clearOutputCmdCheckBox.Checked)
                cmdFilesDataTable_.Clear() ;
            
            updateControlStates();
            statusChanged("Cleared");
        }
        
        private void handleProcessButtonClick(object sender, EventArgs e) 
        {
            if (inputCmdListBox.SelectedIndices.Count == 0) 
                return;
            
            foreach (int i in inputCmdListBox.SelectedIndices) 
            {
                string inputFullName         = cmdFilesDataTable_.Rows[i]["inputFullName"] as string;
                string outputFullName         = cmdFilesDataTable_.Rows[i]["outputFullName"] as string;
                
                processCmdFileRequested(inputFullName, outputFullName, keepEqualSigncheckBox.Checked, skipEmptyLinesCheckBox.Checked);
            }

            updateControlStates();
            statusChanged("CMD file Processed") ;    //HOW to get "true" info here, like validated process status, and filename ???
        }
        
        private void handleInputCmdDoubleClick(object sender, EventArgs e)
        {
            ListBox listBox = sender as ListBox;

            int index = (listBox == null)
                ? ListBox.NoMatches
                : listBox.IndexFromPoint(listBox.PointToClient(Cursor.Position));

            if (index == listBox.SelectedIndex)
            {
                cmdFilesDataTable_.Rows.RemoveAt(index);
                updateControlStates();
            }
        }
        
        private void handleOutputCmdDoubleClick(object sender, EventArgs e)
        {
            ListBox listBox = sender as ListBox;

            int index = (listBox == null)
                ? ListBox.NoMatches
                : listBox.IndexFromPoint(listBox.PointToClient(Cursor.Position));

            if (index == listBox.SelectedIndex)
            {
                clearOutputCmdFile(listBox.SelectedValue as string);
                updateControlStates();
            }
        }
        
        private void handleInputCmdContextMenuItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            string fullName = inputCmdListBox.SelectedValue as string;

            if (string.IsNullOrEmpty(fullName))
                return;
            
            if (e.ClickedItem.Name.Equals("editInputCmdToolStripMenuItem")) {
                editCmdFileRequested(fullName);
            }
            else if (e.ClickedItem.Name.Equals("clearInputCmdToolStripMenuItem")) {
                clearInputCmdFile(fullName);
            }
            
            updateControlStates();
        }
        
        private void handleOutputCmdContextMenuItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            string inputCmdFullName = inputCmdListBox.SelectedValue as string;
            string outputCmdFullName = outputCmdListBox.SelectedValue as string;

            if (string.IsNullOrEmpty(outputCmdFullName))
                return;
            
            if (e.ClickedItem.Name.Equals("editOutputCmdToolStripMenuItem")) {
                editCmdFileRequested(outputCmdFullName);
            }
            else if (e.ClickedItem.Name.Equals("diffOutputCmdToolStripMenuItem")) {
                if (! string.IsNullOrEmpty(inputCmdFullName))
                    diffCmdFilesRequested(inputCmdFullName, outputCmdFullName);
            }
            else if (e.ClickedItem.Name.Equals("clearOutputCmdToolStripMenuItem")) {
                clearOutputCmdFile(outputCmdFullName);
            }
            else if (e.ClickedItem.Name.Equals("deleteOutputCmdToolStripMenuItem")) {
                clearOutputCmdFile(outputCmdFullName);
                deleteCmdFileRequested(outputCmdFullName);
            }

            updateControlStates();
//            statusChanged("FileEntry deleted: " +outputCmdFullName) ;    //move up in if/else structure ??
        }
        
        private void handleCmdInputListBoxDragOver(object sender, DragEventArgs e)
        {
            Object data = e.Data.GetData(typeof(ListBox.SelectedObjectCollection));
            
            e.Effect = ((data as ListBox.SelectedObjectCollection) == null)
                ? DragDropEffects.None 
                : DragDropEffects.Copy;
        }
        
        private void handleCmdInputListBoxDragDrop(object sender, DragEventArgs e)
        {
            Object data = e.Data.GetData(typeof(ListBox.SelectedObjectCollection));
            ListBox.SelectedObjectCollection selection     = data as ListBox.SelectedObjectCollection;
            
            if ((selection == null) || (selection.Count == 0))
                return;
            
            foreach (DataRowView dataRowView in selection)
            {
                if (dataRowView == null)
                    continue;
                
                addInputCmdFileIfExclusive(dataRowView.Row);
            }
        }
        
        private void handleInputCmdButtonClick(object sender, EventArgs e)
        {
            inputCmdFileRequested();
        }
        
        private void handleOutputCmdButtonClick(object sender, EventArgs e)
        {
            if (inputCmdListBox.SelectedIndex == -1)
                return;
            
            int i = inputCmdListBox.SelectedIndex;
            string inputFileName = cmdFilesDataTable_.Rows[i]["inputFileName"] as string;
            string outputFullName = cmdFilesDataTable_.Rows[i]["outputFullName"] as string;
            
            string fileNameHint = string.IsNullOrEmpty(outputFullName)
                ? inputFileName
                : outputFullName;
            
            if (string.IsNullOrEmpty(fileNameHint))
                return;
            
            outputCmdFileRequested(fileNameHint);            
        }
        
        void handleCmdListBoxMouseHover(object sender, EventArgs e)
        {            
            ListBox listBox = sender as ListBox;
            if (listBox == null)
                return;
            
            string columnName = (listBox == inputCmdListBox)
                ? "inputFullName"
                : "outputFullName";
            
            int index = listBox.IndexFromPoint(listBox.PointToClient(Cursor.Position));
            
            string fullName = ((index >= 0) && (index < listBox.Items.Count))
                ? (listBox.Items[index] as DataRowView).Row[columnName] as string
                : null;
                
            if (string.IsNullOrEmpty(fullName))
                cmdListBoxToolTip.RemoveAll();
            else
                cmdListBoxToolTip.SetToolTip(listBox, fullName);            
        }
        
        void handleSelectedIndexChanged(object sender, EventArgs e)
        {
             updateControlStates();
        }

        #endregion        
    }
}
